package net.kazed.nextaction.database.serialize;

import java.io.File;
import java.io.FileNotFoundException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import net.kazed.nextaction.database.GtdAndroid;
import net.kazed.nextaction.database.GtdContext;
import net.kazed.nextaction.database.Task;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;

public class BackupFile {
    
    public static final String URI_SUFFIX = "backup";
    public static final Uri CONTENT_URI = Uri.parse("content://" + GtdAndroid.PACKAGE + "/" + URI_SUFFIX);
    public static final Uri CONTENT_ITEM_URI = Uri.parse("content://" + GtdAndroid.PACKAGE + "/" + URI_SUFFIX + "/#");
    public static final String CONTENT_LIST_TYPE = "vnd.android.cursor.dir/vnd.nextaction.backup";
    public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.nextaction.backup";

    public static final String URI_EXTERNAL_SUFFIX = "backupExternal";
    public static final Uri CONTENT_EXTERNAL_URI = Uri.parse("content://" + GtdAndroid.PACKAGE + "/" + URI_EXTERNAL_SUFFIX);
    public static final String CONTENT_EXTERNAL_LIST_TYPE = "vnd.android.cursor.dir/vnd.nextaction.backupExternal";

    private String fileName;
    private XmlEncoder xmlEncoder = new UrlXmlEncoder();

    /**
     * Constructor
     * @param fileName
     */
    public BackupFile(String fileName) {
        super();
        this.fileName = fileName;
    }

    /**
     * @return File name of this backup.
     */
    public String getFileName() {
        return fileName;
    }

    public void createBackup(Context context) {
        ContentResolver contentResolver = context.getContentResolver();
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH:mm");
        Date date = new Date();
        fileName = "backup-" + dateFormat.format(date) + ".nab";
        XmlWriter xmlWriter;
        try {
            xmlWriter = new XmlWriter(xmlEncoder, context.openFileOutput(fileName, Context.MODE_WORLD_WRITEABLE));
            xmlWriter.startElement("nextaction");
            xmlWriter.addElement("version", "0.6");
            xmlWriter.addElement("createdDate", dateFormat.format(date));

            ContextXmlSerializer serializer = new ContextXmlSerializer(xmlWriter);

            Cursor contextCursor = null;
            try {
                contextCursor = contentResolver.query(GtdContext.CONTENT_URI, GtdContext.FULL_PROJECTION.getFieldNames(),
                                null, null, GtdContext.ID + " ASC");
                contextCursor.moveToFirst();
                while (!contextCursor.isAfterLast()) {
                    GtdContext gtdContext = new GtdContext(contextCursor);
                    serializer.serialize(gtdContext);
                    contextCursor.moveToNext();
                }
            } finally {
                try {
                    contextCursor.close();
                } catch (Exception e) {

                }
            }

            Cursor taskCursor = null;
            try {
                taskCursor = contentResolver.query(Task.CONTENT_URI, Task.FULL_PROJECTION.getFieldNames(), null, null,
                                Task.ID + " ASC");
                taskCursor.moveToFirst();
                while (!taskCursor.isAfterLast()) {
                    Task task = new Task(taskCursor);
                    serializer.serialize(task);
                    taskCursor.moveToNext();
                }
            } finally {
                try {
                    taskCursor.close();
                } catch (Exception e) {

                }
            }
            xmlWriter.endElement();
            xmlWriter.flush();
        } catch (FileNotFoundException e) {
            throw new RuntimeException("Failed to open backup file");
        }
    }

    public void createBackup(Context context, SQLiteDatabase database) {
        ContentResolver contentResolver = context.getContentResolver();
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH:mm");
        Date date = new Date();
        XmlWriter xmlWriter;
        try {
            xmlWriter = new XmlWriter(xmlEncoder, context.openFileOutput(fileName, Context.MODE_WORLD_WRITEABLE));
            xmlWriter.startElement("nextaction");
            xmlWriter.addElement("version", "0.6");
            xmlWriter.addElement("createdDate", dateFormat.format(date));

            ContextXmlSerializer serializer = new ContextXmlSerializer(xmlWriter);

            Cursor contextCursor = null;
            try {
                contextCursor = contentResolver.query(GtdContext.CONTENT_URI, GtdContext.FULL_PROJECTION.getFieldNames(),
                                null, null, GtdContext.ID + " ASC");
                contextCursor.moveToFirst();
                while (!contextCursor.isAfterLast()) {
                    GtdContext gtdContext = new GtdContext(contextCursor);
                    serializer.serialize(gtdContext);
                    contextCursor.moveToNext();
                }
            } finally {
                try {
                    contextCursor.close();
                } catch (Exception e) {

                }
            }

            Cursor taskCursor = null;
            try {
                taskCursor = contentResolver.query(Task.CONTENT_URI, Task.FULL_PROJECTION.getFieldNames(), null, null,
                                Task.ID + " ASC");
                taskCursor.moveToFirst();
                while (!taskCursor.isAfterLast()) {
                    Task task = new Task(taskCursor);
                    serializer.serialize(task);
                    taskCursor.moveToNext();
                }
            } finally {
                try {
                    taskCursor.close();
                } catch (Exception e) {

                }
            }
            xmlWriter.endElement();
            xmlWriter.flush();
        } catch (FileNotFoundException e) {
            throw new RuntimeException("Failed to open backup file");
        }
    }

    /**
     * Restore from backup.
     * 
     * @param context Android context.
     * @param fileName Backup file name.
     */
    public void restoreMergeBackup(Context context) {
        BackupRootHandler rootHandler = new BackupRootHandler(context.getContentResolver());
        XmlParser xmlParser = new XmlParser(xmlEncoder, rootHandler);
        File file = context.getFileStreamPath(fileName);
        xmlParser.parse(file);
    }

    /**
     * Restore from backup.
     * 
     * @param context Android context.
     * @param fileName Backup file name.
     */
    public void restoreReplaceBackup(Context context) {
        ContentResolver contentResolver = context.getContentResolver();
        BackupRootHandler rootHandler = new BackupRootHandler(contentResolver);
        XmlParser xmlParser = new XmlParser(xmlEncoder, rootHandler);
        File file = context.getFileStreamPath(fileName);
        xmlParser.parse(file);
    }
    
    /**
     * Restore from backup.
     * 
     * @param context Android context.
     * @return Summary of backup file contents.
     */
    public BackupFileSummary getBackupSummary(Context context) {
        BackupSummaryRootHandler rootHandler = new BackupSummaryRootHandler();
        XmlParser xmlParser = new XmlParser(xmlEncoder, rootHandler);
        File file = context.getFileStreamPath(fileName);
        xmlParser.parse(file);
        return rootHandler.getBackupFileSummary();
    }

}
